<?php
namespace Core\CoreComponents\AccountingManager;
use Core;

require_once(COMPONENTS_DIR . 'DocumentsManager/FileSystemHelpers.php');
require_once(COMPONENTS_DIR . 'AccountingManager/ICategories.php');
require_once(CONTRACTS_DIR . 'category.entity.php');

/**
* This class provide all accessible methods on Category module
*
* @method ServiceResponse getCategories($accountId)
* @method ServiceResponse getCategorie($accountName, $categoryName)
* @method ServiceResponse addCategory($accountName, $name, $parentId)
* @method ServiceResponse deleteCategory($id)
* @method ServiceResponse SynchronizeCategoriesToFolders($idAccount, $rootPath)
* @method ServiceResponse SynchronizeFoldersToCategories($idAccount, $rootPath)
* @method ServiceResponse getCategorieFromId($id)
*/
class Categories implements ICategories
{

	/**
	 * Get all categories from an account
	 * 
	 * @param integer $accountId The account id
	 *
	 * @return ServiceResponse This response contains all categories from the targeted account
	 */
    public function getCategories($accountId)
	{
		Core\CoreCommons\Logger::Info("getCategories $accountId");
		
		$response = null;
		
		try
		{	
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
		
			$session->CreateCriteria('Category');
			$session->AddCriteria(Expression::SQL_EQ('Account', $accountId));
			$result = $session->ListResult();
			
			$response = new Core\CoreCommons\ServiceResponse($result);

			$session->Close();
			
			Core\CoreCommons\Logger::Info("getCategories");
		}
		catch (Exception $ex) 
		{
			$response = ServiceResponse::CreateError($ex);
		}
		
		return $response;
	}
	
	/**
	 * Get category from an account and a name
	 * 
	 * @todo This method should take an account id instead of account name
	 * @param string $accountName The account name targeted
	 * @param string $categoryName The category name targeted
	 *
	 * @return ServiceResponse This response contains the targeted category from the selected account
	 */
    public function getCategorie($accountName, $categoryName)
	{
		Core\CoreCommons\Logger::Info("getCategorie $accountName, $categoryName");
		
		$response = null;
		
		try
		{	
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
		
			$session->CreateCriteria('Category');
			$session->AddCriteria(Expression::SQL_EQ('Account', $accountName));
			$session->AddCriteria(Expression::SQL_EQ('Name', $categoryName));
			$result = $session->UniqueResult();
			
			$response = new Core\CoreCommons\ServiceResponse($result);

			$session->Close();
			
			Core\CoreCommons\Logger::Info("getCategorie");
		}
		catch (Exception $ex) 
		{
			$response = ServiceResponse::CreateError($ex);
		}
		
		return $response;
	}
	
	/**
	 * Get category form an id
	 *
	 * @param integer $id The category identifier
	 * 
	 * @return ServiceResponse The response contains the targeted category
	 */
    public function getCategorieFromId($id)
	{
		Core\CoreCommons\Logger::Info("getCategorie $id");
		
		$response = null;
		
		try
		{	
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
		
			$result = $session->Load('Category', $id);
			
			$response = new Core\CoreCommons\ServiceResponse($result);

			$session->Close();
		}
		catch (Exception $ex) 
		{
			$response = ServiceResponse::CreateError($ex);
		}
		
		return $response;
	}
	
	/**
	 * Add a category
	 * 
	 * @todo This method should take an account id instead of account name
	 * @param string $accountName The account name targeted
	 * @param string $name The category name
	 * @param string $parentId The parent category
	 *
	 * @return ServiceResponse This response contains the added category
	 */
    public function addCategory($accountName, $name, $parentId, $path = "\\")
	{
		Core\CoreCommons\Logger::Info("addCategory $accountName, $name, $parentId, $path");
		
		$response = null;
		
		try
		{	
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
			
			$session->CreateCriteria('Account');
			$session->AddCriteria(Expression::SQL_EQ('Name', $accountName));
			$account = $session->UniqueResult();

			if(isset($parentId) == false || $parentId == '')
			{
				$parentId = 0;
			}
			else
			{
				$parent = $session->Load('Category', $parentId);
				$path .= $parent->Path . DIRECTORY_SEPARATOR . $name;
			}
			$path = str_replace("\\", "/", $path);
			$category = Category::Create($account->Id, $name, $parentId, $path);
			
			$result = $session->Save($category);
			$response = new Core\CoreCommons\ServiceResponse($result);

			$session->Close();
			Core\CoreCommons\Logger::Info("Category $accountName, $name, $parentId added");
		}
		catch (Exception $ex) 
		{
			$response = ServiceResponse::CreateError($ex);
		}
		
		return $response;
	}
	
	/**
	 * Delete a category
	 *
	 * @param integer $id The category identifier
	 * 
	 * @return ServiceResponse The response contains the deleted category
	 */
    public function deleteCategory($id)
	{
		Core\CoreCommons\Logger::Info("deleteCategory $id");
		
		$response = null;
		
		try
		{	
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
			
			$category = $session->Load('Category', $id);

			$result = $session->Delete($category);
			$response = new Core\CoreCommons\ServiceResponse($result);

			$session->Close();
			Core\CoreCommons\Logger::Info("Category $id deleted");
		}
		catch (Exception $ex) 
		{
			$response = ServiceResponse::CreateError($ex);
		}
		
		return $response;
	}
	
	/**
	 * Synchronize categories to folders
	 * 
	 * @param integer $idAccount The targeted account identifier
	 * @param string $rootPath The targeted root path to synchronize folders
	 *
	 * @return ServiceResponse The response contains a true boolean if success
	 */
    public function synchronizeCategoriesToFolders($idAccount, $rootPath)
	{
		Core\CoreCommons\Logger::Info("SynchronizeCategoriesToFolders $idAccount, $rootPath");
		
		$response = null;
		
		try
		{	
			//Get all categories
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
			$session->CreateCriteria('Category');
			$session->AddCriteria(Expression::SQL_EQ('Account', $idAccount));
			$categories = $session->ListResult();
			$session->Close();
			
			//Get account
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
			$account = $session->Load('Account', $idAccount);
			$session->Close();
			
			//Get all folders
			$fileSystemHelpers = new FileSystemHelpers();
			$folders = array();
			$fileSystemHelpers->GetFolders($rootPath, $folders);
			
			//Merge all data
			foreach($categories as &$category)
			{
				if (in_array($category->Name, $folders) == false) 
				{
					$newFolder = $rootPath . $category->Path;
					$parts = explode(DIRECTORY_SEPARATOR, $category->Path);
					$pathToCreateFolder = $rootPath;
					foreach($parts as $folder) 
					{
						$pathToCreateFolder .= $folder . "/" ;
						if(file_exists($pathToCreateFolder) == false)
						{
							Core\CoreCommons\Logger::Info("synchronizeCategoriesToFolders - create folder $pathToCreateFolder");
							mkdir($pathToCreateFolder);
						}
					}
				}
			}

			Core\CoreCommons\Logger::Info("SynchronizeCategoriesToFolders finished");
		}
		catch (Exception $ex) 
		{
			$response = ServiceResponse::CreateError($ex);
		}
		
		return $response;
	}
	
	/**
	 * Synchronize folders to categories
	 * 
	 * @param integer $idAccount The targeted account identifier
	 * @param string $rootPath The targeted root path to synchronize folders
	 *
	 * @return ServiceResponse The response contains a true boolean if success
	 */
    public function synchronizeFoldersToCategories($idAccount, $rootPath)
	{
		Core\CoreCommons\Logger::Info("SynchronizeFoldersToCategories $idAccount, $rootPath");
		
		$response = null;
		
		try
		{	
			//Get all categories
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
			$session->CreateCriteria('Category');
			$session->AddCriteria(Expression::SQL_EQ('Account', $idAccount));
			$categories = $session->ListResult();
			$session->Close();
			$categoryNames = array();
			foreach($categories as &$category)
			{
				array_push($categoryNames, $category->Name);
			}
			
			//Get account
			$session = Core\Datastorage\Session::Instance();
			$session->Open();
			$account = $session->Load('Account', $idAccount);
			$session->Close();
			
			//Get all folders
			$fileSystemHelpers = new FileSystemHelpers();
			$folders = array();
			$fileSystemHelpers->GetFolders($rootPath, $folders);
			
			Core\CoreCommons\Logger::Info("SynchronizeFoldersToCategories - Folder number : " . count($folders));
			
			//Merge all data
			foreach($folders as &$folder)
			{
				
				if (in_array($folder, $categoryNames) == false) 
				{
					Core\CoreCommons\Logger::Info("synchronizeFoldersToCategories - Add $folder on categories");
					$parentId = $this->GetParentIdFromFolder($folder, $categories);
					$folder = str_replace($rootPath, "/", $folder);
					$this->addCategory($account->Name, basename($folder), $parentId, $folder);
				}
			}

			Core\CoreCommons\Logger::Info("SynchronizeFoldersToCategories finished");
		}
		catch (Exception $ex) 
		{
			$response = ServiceResponse::CreateError($ex);
		}
		
		return $response;
	}
	
	/**
	 * Get the category parent id from a folder
	 * 
	 * @param string $folder The targeted account identifier
	 * @param array $categories The categories array to parse
	 *
	 * @return ServiceResponse The response contains the parent id from the folder or 0 by default
	 */
	private function GetParentIdFromFolder($folder, $categories)
	{
		$parentId = 0;
		
		foreach($categories as &$category)
		{
			if($category->Name == $folder)
			{
				$parentId = $category->ParentCategory;
				break;
			}
		}
		
		return $parentId;
	}
}

?> 